/*
 * Copyright (C) 2009 Yury Kudryashov.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package name.kudryashov.collections;

import java.util.HashSet;
import java.util.Set;
import java.util.Arrays;

/**
 * Utility methods for working with {@link java.util.Set}s.
 */
public class Sets {

    private Sets() {}

    /**
     * Creates a new hash set with all elements of the given set added.
     * @param base set to copy to the new set, not null
     * @param <E> type of the element
     * @return a new set@
     * @throws NullPointerException base is null
     */
    public static <E> Set<E> newHashSet(Set<? extends E> base) {
        return new HashSet<E>(base);
    }

    /**
     * Creates a new hash set with the given elements added.
     * @param elems elements to add, not null
     * @param <E> type of the element
     * @return a new set@
     * @throws NullPointerException elems is null
     */
    public static <E> Set<E> newHashSet(E... elems) {
        Set<E> set = new HashSet<E>(elems.length);
        set.addAll(Arrays.asList(elems));
        return set;
    }

    /**
     * Returns a new set that is a union of the given sets.
     * @param sets sets to union, not null
     * @param <E> type of elements in the set
     * @return a new set containing all the elements from all the given sets
     * @throws NullPointerException sets is null or any of the set in the sets is null
     */
    public static <E> Set<E> union(Set<? extends E>... sets) {
        Set<E> union = newHashSet();
        for(Set<? extends E> set : sets) union.addAll(set);
        return union;
    }

    /**
     * Returns a new set that is an intersection of the given sets.
     * @param sets sets to intersect, not null
     * @param <E> type of elements in the set
     * @return a new set containing only the elements that are present in all the given sets
     * @throws NullPointerException sets is null or any of the set in the sets is null
     */
    public static <E> Set<E> intersect(Set<? extends E>... sets) {
        Set<E> intersection = newHashSet();
        if(sets.length > 0) {
            intersection.addAll(sets[0]);
            for(int i = 1; i < sets.length; i++) {
                intersection.retainAll(sets[i]);
            }
        }
        return intersection;
    }

    /**
     * Returns a new set that contains a difference between the two given sets (contains only the
     * elements present in set1 and not present in set2.
     * @param set1 first set, not null
     * @param set2 second set, not null
     * @param <E> type of elements
     * @return a new set containing all elements present in {@code set1} and not present in {@code set2}
     */
    public static <E> Set<E> diff(Set<? extends E> set1, Set<? extends E> set2) {
        Set<E> diff = newHashSet(set1);
        diff.removeAll(set2);
        return diff;
    }
}
